#pragma once

#include <iostream>
#include <string>
#include <cstdio> // printf

#include <sys/types.h> //key_t
#include <sys/ipc.h>   //ftok
#include <sys/shm.h>   //shmget
#include <unistd.h>

const std::string _path = "/home/ubuntu/Ubuntu/ubunto-learning";
int _pjid = 0x6666;
ssize_t _size = 1024;
mode_t _mode = 0600;

std::string _tsformat(key_t _k) // 转16进制
{
    char _buffer[64];
    snprintf(_buffer, sizeof(_buffer), "0x%x", _k); // 第一个参数就是数组，目标数组，这个字符串足够最大以容纳格式化输出
    return _buffer;
}

class ShareMemory
{
public:
    // 共享内存的初始化 和 析构函数
    ShareMemory() : // 函数初始化
                    _key(0),
                    _ret(nullptr), // 这里的nullptr表示的意思就是 择股地址还没有被创建
                    _shmid(-1)     // 这里的-1 表示_shmid的状态 如果还没创造过那么就是为-1
    {
    }
    ~ShareMemory() {}

    // 共享内存的创建
    void CreateShareMemory()
    {
        if (_shmid == -1)
        {
            ShmHelper(IPC_CREAT | IPC_EXCL | _mode); // 创建成功 是一个新的共享内存
        }
    }

    // 获得共享内存
    void GetMemory()
    {
        ShmHelper(IPC_CREAT);
    }

    void AttachShm()
    {
        _ret = ::shmat(_shmid, nullptr, 0);
        if ((long long)_ret == -1)
        {
            std::cout << "AttachShm failed!" << std::endl;
        }
    }

    void DetachShm()
    {
        if (_ret != nullptr)
        {
            ::shmdt(_ret);
            std::cout << "DetachShm() successful!" << std::endl;
        }
    }

    void DetShm()
    {
        int _isitshmdel = ::shmctl(_shmid, IPC_RMID, nullptr);

        if (_isitshmdel == 0)
        {
            std::cout << "DetShm() successful!" << std::endl;
        }
    }

    int GetKey()
    {
        return _key;
    }

    int GetShmid()
    {
        return _shmid;
    }

    void *GetRet()
    {
        return _ret;
    }

private:
    void ShmHelper(int shmlag) // 这个shmlag 表示的意思就是 权限的设置
    {
        _key = ::ftok(_path.c_str(), _pjid);
        // (1)得到一个 共享标识符
        if (_key < 0) // 判定
        {
            std::cerr << "ftok error" << std::endl;
        }
        std::cout << "_key: " << _tsformat(_key) << std::endl;

        // (2)创建共享内存 && 获取
        _shmid = shmget(_key, _size, shmlag); // 这里单独带一个 就是表示获取 不一定会重新拿一个新的共享内存
        if (_shmid < 0)                       // 判定
        {
            std::cerr << "Shmget Error!" << std::endl;
        }
    }

    int _key;
    void *_ret;
    int _shmid;
};

ShareMemory _shm1;
